﻿using HslCommunication;
using HslCommunication.Profinet.Siemens;
using System;

namespace SSC.PlcConnect
{
    /// <summary>
    /// 西门子S7-1200实现类，符合IPlcConnect接口
    /// </summary>
    internal class SiemensPlc : IPlcConnect
    {
        private static SiemensPlc _instance; // 单例实例
        private static readonly object _lock = new object(); // 线程锁，确保线程安全

        private SiemensS7Net _siemensS7Net; // 西门子 S7 协议实现

        public string IpAddress { get; private set; }
        public int Port { get; private set; }
        public bool IsConnected { get; private set; }

        private SiemensPlc(string ipAddress, int port)
        {
            IpAddress = ipAddress;
            Port = port;
            IsConnected = false;
            _siemensS7Net = new SiemensS7Net(SiemensPLCS.S200Smart) // 选择 S7300 或其他型号
            {
                IpAddress = IpAddress,
                Port = Port
            };
        }

        /// <summary>
        /// 初始化实例
        /// </summary>
        /// <param name="ipAddress">PLC IP地址</param>
        /// <param name="port">PLC端口号</param>
        public static void Initialize(string ipAddress, int port = 102) // 默认为102端口
        {
            lock (_lock)
            {
                if (_instance != null)
                {
                    throw new InvalidOperationException("PLC连接已初始化，不能重复初始化！");
                }

                _instance = new SiemensPlc(ipAddress, port);
            }
        }

        /// <summary>
        /// 获取实例
        /// </summary>
        /// <returns>PLC连接实例</returns>
        public static SiemensPlc GetInstance()
        {
            if (_instance == null)
            {
                throw new InvalidOperationException("PLC连接尚未初始化，请先调用 Initialize 方法！");
            }
            return _instance;
        }

        /// <summary>
        /// 连接到PLC（异步）
        /// </summary>
        /// <returns>是否连接成功</returns>
        public async Task<bool> ConnectAsync()
        {
            try
            {
                lock (_lock)
                {
                    if (IsConnected)
                    {
                        Console.WriteLine("已连接到PLC，无需重复连接！");
                        return true;
                    }
                }

                OperateResult connectResult = await _siemensS7Net.ConnectServerAsync();
                if (connectResult.IsSuccess)
                {
                    IsConnected = true;
                    Console.WriteLine("成功连接到PLC！");
                    return true;
                }
                else
                {
                    Console.WriteLine($"连接失败: {connectResult.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"连接过程中发生异常: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 读取PLC数据（异步）读取单个地址值ushort
        /// </summary>
        /// <param name="address">地址</param>
        /// <returns>读取的值</returns>
        public async Task<short> ReadSingle(string address)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("请先连接到PLC！");
            }

            try
            {
                // 使用 SiemensS7Net 读取单个数据
                OperateResult<ushort> result = await Task.Run(() => _siemensS7Net.ReadUInt16(address));
                if (result.IsSuccess)
                {
                    Console.WriteLine($"成功读取地址 {address} 数据：{result.Content}");
                    return (short)result.Content;
                }
                else
                {
                    Console.WriteLine($"读取失败: {result.Message}");
                    return default;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取数据时发生异常: {ex.Message}");
                return default;
            }
        }

        /// <summary>
        /// 批量读取PLC数据（异步）读取多个地址的 ushort 数组
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度（ushort 个数）</param>
        /// <returns>读取的值数组</returns>
        public async Task<short[]> ReadBatch(string startAddress, ushort length)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("请先连接到PLC！");
            }

            try
            {
                // 使用 SiemensS7Net 读取多个数据
                OperateResult<ushort[]> result = await Task.Run(() => _siemensS7Net.ReadUInt16(startAddress, length));
                if (result.IsSuccess)
                {
                    Console.WriteLine($"成功读取起始地址 {startAddress} 长度 {length} 的数据：{string.Join(", ", result.Content)}");
                    return result.Content.Select(v => (short)v).ToArray();
                }
                else
                {
                    Console.WriteLine($"批量读取失败: {result.Message}");
                    return null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量读取数据时发生异常: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 写入PLC数据（异步）写入 单个Int16 数据
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">数据</param>
        /// <returns>是否写入成功</returns>
        public async Task<bool> WriteSingle(string address, short value)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("请先连接到PLC！");
            }

            try
            {
                OperateResult result = await _siemensS7Net.WriteAsync(address, (ushort)value);
                if (result.IsSuccess)
                {
                    Console.WriteLine($"成功写入地址 {address} 数据：{value}");
                    return true;
                }
                else
                {
                    Console.WriteLine($"写入失败: {result.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入数据时发生异常: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 写入PLC数据（异步）批量写入多个Int16 数据
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="values">数据数组</param>
        /// <returns>是否写入成功</returns>
        public async Task<bool> WriteBatch(string startAddress, short[] values)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("请先连接到PLC！");
            }

            try
            {
                OperateResult result = await _siemensS7Net.WriteAsync(startAddress, values.Select(v => (ushort)v).ToArray());
                if (result.IsSuccess)
                {
                    Console.WriteLine($"成功批量写入数据到起始地址 {startAddress}");
                    return true;
                }
                else
                {
                    Console.WriteLine($"批量写入失败: {result.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量写入数据时发生异常: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 读取PLC布尔值（单个地址）
        /// </summary>
        /// <param name="address">PLC地址，例如 "M0.0" 或 "DB1.0.0"</param>
        /// <returns>读取的布尔值</returns>
        public async Task<bool> ReadBool(string address)
        {
            if (!IsConnected)
                throw new InvalidOperationException("PLC未连接");

            var result = await Task.Run(() => _siemensS7Net.ReadBool(address));
            if (result.IsSuccess)
            {
                return result.Content;
            }
            else
            {
                throw new Exception($"读取布尔值失败，地址: {address}，原因: {result.Message}");
            }
        }

        /// <summary>
        /// 批量读取PLC布尔值（连续地址）
        /// </summary>
        /// <param name="address">起始地址，例如 "M0.0"</param>
        /// <param name="length">读取的位数</param>
        /// <returns>布尔值数组</returns>
        public async Task<bool[]> ReadBoolBatch(string address, ushort length)
        {
            if (!IsConnected)
                throw new InvalidOperationException("PLC未连接");

            var result = await Task.Run(() => _siemensS7Net.ReadBool(address, length));
            if (result.IsSuccess)
            {
                return result.Content;
            }
            else
            {
                throw new Exception($"批量读取布尔值失败，起始地址: {address}，原因: {result.Message}");
            }
        }


        /// <summary>
        /// 断开PLC连接
        /// </summary>
        public void Disconnect()
        {
            lock (_lock)
            {
                if (IsConnected)
                {
                    _siemensS7Net.ConnectClose();
                    IsConnected = false;
                    Console.WriteLine("已断开与PLC的连接。");
                }
                else
                {
                    Console.WriteLine("PLC未连接，无需断开！");
                }
            }
        }
    }
}
